﻿using System;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using System.Collections.Generic;
using NHibernate.Util;

namespace RG.Common.Provider
{

    /// <summary>
    /// An <see cref="ICriterion"/> that represents an "starting with" constraint.
    /// </summary>
    [Serializable]
    public class StartingWithExpression : AbstractCriterion
    {
        private readonly string value;
        private readonly IProjection projection;

        public StartingWithExpression(string propertyName, string value)
        {
            projection = Projections.Property(propertyName);
            this.value = value;
        }


        #region ICriterion Members

        internal static SqlString[] GetColumnNamesUsingProjection(IProjection projection, ICriteriaQuery criteriaQuery, ICriteria criteria,
                                                                     IDictionary<string, IFilter> enabledFilters)
        {
            SqlString sqlString = projection.ToSqlString(criteria,
                criteriaQuery.GetIndexForAlias(),
                criteriaQuery,
                enabledFilters);
            return new[]
				{
					StringHelper.RemoveAsAliasesFromSql(sqlString)
				};
        }

        public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
        {
            SqlString[] columns = GetColumnNamesUsingProjection(projection, criteriaQuery, criteria, enabledFilters);
            if (columns.Length != 1)
                throw new HibernateException("Like may only be used with single-column properties / projections.");

            var lhs = new SqlStringBuilder(6);

            lhs.Add(columns[0]);

            criteriaQuery.AddUsedTypedValues(GetTypedValues(criteria, criteriaQuery));

            lhs.Add(" starting with ").AddParameter();

            return lhs.ToSqlString();
        }

        public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
        {
            return new[] {
								new TypedValue(NHibernateUtil.String, value, EntityMode.Poco),
			                        };
        }

        public override IProjection[] GetProjections()
        {
            return new[] { projection };
        }

        #endregion

        public override string ToString()
        {
            return projection + " starting with " + value;
        }
    }

}

